﻿#region COPYRIGHT© 2009-2013 Phillip Clark. All rights reserved.

// For licensing information see License.txt (MIT style licensing).

#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace FlitBit.Json
{
	public abstract class JsonMember : JsonNode, ICollection<JsonValue>
	{
		protected JsonMember(string name, JsonValue value)
			: base(JsonNodeKind.Member)
		{
			Contract.Requires<ArgumentNullException>(name != null);
			Contract.Requires<ArgumentException>(name.Length > 0);
			Contract.Requires<ArgumentNullException>(value != (JsonValue) null, "value cannot be null");

			if (name.Length > 1)
			{
				if (name[0] == '\'' && name[name.Length - 1] == '\'')
				{
					Name = name.Substring(1, name.Length - 2)
										.Replace("''", "'");
				}
				else if (name[0] == '"' && name[name.Length - 1] == '"')
				{
					Name = name.Substring(1, name.Length - 2)
										.Replace("\"\"", "\"");
				}
				else
				{
					Name = name;
				}
			}
			else
			{
				Name = name;
			}

			this.Value = value;
		}

		public string Name { get; private set; }
		public JsonValue Value { get; protected set; }

		public override string ToString()
		{
			return new JsonFormatter().Write(this)
																.ToString();
		}

		protected internal virtual void PerformBreadthFirstTransformFilter(Func<JsonNode, JsonNode> filter)
		{
			var v = Value;
			var n = filter(v);
			if (!ReferenceEquals(n, v))
			{
				if (n is JsonValue)
				{
					Value = n as JsonValue;
				}
				else
				{
					throw new InvalidOperationException("A filter returned an invalid JsonNode, the value cannot be replaced.");
				}
			}
			else
			{
				v.PerformBreadthFirstTransformFilter(filter);
			}
		}

		protected internal virtual void PerformDepthFirstTransformFilter(Func<JsonNode, JsonNode> filter)
		{
			var v = Value;
			v.PerformDepthFirstTransformFilter(filter);

			var n = filter(v);
			if (!ReferenceEquals(n, v))
			{
				if (n is JsonValue)
				{
					Value = n as JsonValue;
				}
				else
				{
					throw new InvalidOperationException("A filter returned an invalid JsonNode, the value cannot be replaced.");
				}
			}
		}

		protected internal override void WriteFormatted(JsonFormatter formatter)
		{
			formatter.WriteNameValuePair(Name, Value);
		}

		#region ICollection<JsonValue> Members

		public abstract void Add(JsonValue item);

		public abstract void Clear();

		public abstract bool Contains(JsonValue item);

		public abstract void CopyTo(JsonValue[] array, int arrayIndex);

		public abstract int Count { get; }

		public abstract bool IsReadOnly { get; }

		public abstract bool Remove(JsonValue item);

		public abstract IEnumerator<JsonValue> GetEnumerator();

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion

		internal static JsonMember MakeMember(string name, JsonValue value)
		{
			if (value.Kind == JsonNodeKind.Object)
			{
				return new JsonMemberObject(name, value as JsonObject);
			}
			else if (value.Kind == JsonNodeKind.Array)
			{
				return new JsonMemberArray(name, value as JsonArray);
			}
			else
			{
				return new JsonMemberValue(name, value);
			}
		}
	}
}